#include "stdafx.h"
#include "CustomActionHelpers.h"

using namespace MSHelpServices;

class ComInit
{
public:
    ComInit() { ::CoInitialize(NULL); }
    ~ComInit() { ::CoUninitialize(); }
};
static ComInit StaticInit;

class ChangeDir
{
    TCHAR OldPath[MAX_PATH];

    void SetDir(const TCHAR* Path)
    {
        if(!::SetCurrentDirectory(Path))
            throw FusionWare::MSI::Exception(_T("Failed to set current directory"), GetLastError());
    }

public:
    ChangeDir(CString& Path)
    {
        ::GetCurrentDirectory(MAX_PATH, OldPath);
        if(!::SetCurrentDirectory(Path))
            throw FusionWare::MSI::Exception(_T("Failed to set current directory"), GetLastError());
    }

    ~ChangeDir()
    {
        SetDir(this->OldPath);
    }
};

typedef void (*RegOp)( IHxRegisterPtr Reg, IHxPlugInPtr PlugIn );
static void PerformHxRegOp(RegOp Op);

// Utility functions
static void RegisterHelp( IHxRegisterPtr pReg, IHxPlugInPtr pPlugIn )
{
    // for now just hard code the data
    pReg->RegisterNamespace( "FW.SPOT", "FusionWare_SPOT.HxC", "FusionWare.SPOT SDK Documentation" );
    pReg->RegisterHelpFile( "FW.SPOT", "FusionWare_Docs", 1033, "FusionWare_Docs.Hxs" );
    pReg->RegisterHelpFile( "FW.SPOT", "FusionWare_Ref", 1033, "FusionWare_Ref.Hxs" );
    pPlugIn->RegisterHelpPlugIn( "MSVS.PSDK", "_DEFAULT", "FW.SPOT", "_DEFAULT", "", 0 );
}

static void UnregisterHelp( IHxRegisterPtr pReg, IHxPlugInPtr pPlugIn )
{
    // For now just hardcode the data
    pPlugIn->RemoveHelpPlugIn("MSVS.PSDK", "_DEFAULT", "FW.SPOT", "_DEFAULT", "" );
    pReg->RemoveHelpFile( "FW.SPOT", "FusionWare_Docs", 1033);
    pReg->RemoveHelpFile( "FW.SPOT", "FusionWare_Ref", 1033);
    pReg->RemoveNamespace( "FW.SPOT" );
}

static void MergeIndex(_bstr_t Namespace)
{
    IHxSessionPtr pSession(__uuidof(HxSession));
    
    // Need to merge the top most namespace for the application
    // (VS in this case) to prevent auto-merge on first use
    pSession->Initialize( Namespace, 0 );
    pSession->Collection->MergeIndex( );
}

// handles transacted operations with auto revert on exceptions
void PerformHxRegOp(RegOp Op)
{
    _bstr_t txId;
    IHxRegisterSessionPtr pSession(__uuidof(HxRegisterSession));
    try
    {
        txId = pSession->CreateTransaction(txId);

        IHxRegisterPtr pReg(pSession->GetRegistrationObject(HxRegisterSession_IHxRegister));
        IHxPlugInPtr pPlugIn(pSession->GetRegistrationObject(HxRegisterSession_IHxPlugIn));
    
        Op(pReg, pPlugIn);
    
        pSession->CommitTransaction();
    }
    catch(...)
    {
        // always revert the transaction or a system reboot is required
        // to clear it if the id is lost.
        if(!!txId)
            pSession->RevertTransaction();
        
        throw;
    }
}

void RegisterHelpAction(FusionWare::MSI::Session& Session)
{
    std::vector<CString> args = Session.GetCustomActionData(1);
    
    // scope block for directory change
    {
        ChangeDir dir(args[0]);
        PerformHxRegOp(RegisterHelp);

        // merge the complete VS combined collection now
        // to prevent the long auto-merge delay on next help
        // use. It's better to wait at install time instead of 
        // when you need the help system at some later point.
        MergeIndex("ms-help://MS.VSCC.v80");
    }
}

void UnregisterHelpAction(FusionWare::MSI::Session& Session)
{
    std::vector<CString> args = Session.GetCustomActionData(1);
    
    // scope block for directory change
    {
        ChangeDir dir(args[0]);
        PerformHxRegOp(UnregisterHelp);

        // merge the complete VS combined collection now
        // to prevent the long auto-merge delay on next help
        // use. It's better to wait at install time instead of 
        // when you need the help system at some later point.
        MergeIndex("ms-help://MS.VSCC.v80");
    }
}

// Exported Custom Actions
extern "C"
{
    UINT __stdcall RegisterHelp(MSIHANDLE hInstall)
    {
        FusionWare::MSI::Session session(hInstall);
        return session.DoCustomAction( RegisterHelpAction );
    }

    UINT __stdcall UnregisterHelp(MSIHANDLE hInstall)
    {
        FusionWare::MSI::Session session(hInstall);
        return session.DoCustomAction( UnregisterHelpAction );
    }
}
